package com.SmartClassroom.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.SmartClassroom.system.annotation.AuthCheck;
import com.SmartClassroom.system.common.BaseResponse;
import com.SmartClassroom.system.common.DeleteRequest;
import com.SmartClassroom.system.common.ErrorCode;
import com.SmartClassroom.system.common.ResultUtils;
import com.SmartClassroom.system.constant.GradeConstant;
import com.SmartClassroom.system.constant.UserConstant;
import com.SmartClassroom.system.exception.BusinessException;
import com.SmartClassroom.system.exception.ThrowUtils;
import com.SmartClassroom.system.model.domain.Course;
import com.SmartClassroom.system.model.domain.Grade;
import com.SmartClassroom.system.model.domain.User;
import com.SmartClassroom.system.model.dto.grade.GradeAddRequest;
import com.SmartClassroom.system.model.dto.grade.GradeQueryRequest;
import com.SmartClassroom.system.model.dto.grade.GradeUpdateRequest;
import com.SmartClassroom.system.model.vo.GradeVO;
import com.SmartClassroom.system.service.CourseService;
import com.SmartClassroom.system.service.GradeService;
import com.SmartClassroom.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 成绩接口
 *
 * @author baijiayu
 */
@RestController
@RequestMapping("/grade")
@Slf4j
@Api(tags = { "成绩接口" })
public class GradeController {

    @Resource
    private UserService userService;

    @Resource
    private CourseService courseService;

    @Resource
    private GradeService gradeService;

    // region 增删改查

    /**
     * 新增成绩
     *
     * @param gradeAddRequest
     * @return
     */
    @PostMapping("/add")
    @ApiOperation(value = "新增成绩")
    public BaseResponse<Integer> addGrade(@RequestBody GradeAddRequest gradeAddRequest) {
        if (gradeAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数错误");
        }
        Grade grade = new Grade();
        QueryWrapper<User> userQuery = new QueryWrapper<>();
        QueryWrapper<Course> courseQuery = new QueryWrapper<>();
        userQuery.eq("userName", gradeAddRequest.getStudentName());
        courseQuery.eq("courseName", gradeAddRequest.getCourseName());
        switch (gradeAddRequest.getGradeType()) {
            case "期末成绩":
                gradeAddRequest.setGradeType(GradeConstant.FINAL);
                break;
            case "期中成绩":
                gradeAddRequest.setGradeType(GradeConstant.MIDDLE);
                break;
            case "实验成绩":
                gradeAddRequest.setGradeType(GradeConstant.PROJECT);
                break;
            case "测验成绩":
                gradeAddRequest.setGradeType(GradeConstant.TEST);
                break;
        }
        User userOne = userService.getOne(userQuery);
        // 获取课程列表
        List<Course> courseList = courseService.list(courseQuery);
        if (courseList.isEmpty()) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "课程不存在");
        }
        // 使用第一条记录
        Course courseOne = courseList.get(0);
        grade.setStudentId(userOne.getId());
        grade.setCourseId(courseOne.getCourseId());
        BeanUtils.copyProperties(gradeAddRequest, grade);
        boolean result = gradeService.save(grade);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(grade.getGradeId());
    }

    /**
     * 删除成绩
     *
     * @param deleteRequest
     * @return
     */
    @PostMapping("/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @ApiOperation(value = "删除成绩")
    public BaseResponse<Boolean> deleteUser(@RequestBody DeleteRequest deleteRequest) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean result = gradeService.removeById(deleteRequest.getId());
        return ResultUtils.success(result);
    }

    /**
     * 更新成绩(仅老师和管理员)
     *
     * @param gradeUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新成绩(仅老师和管理员)")
    public BaseResponse<Boolean> updateUser(@RequestBody GradeUpdateRequest gradeUpdateRequest) {
        if (gradeUpdateRequest == null || gradeUpdateRequest.getGradeId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        QueryWrapper<Grade> gradeQuery = new QueryWrapper<>();
        gradeQuery.eq("gradeId", gradeUpdateRequest.getGradeId());
        Grade grade = gradeService.getOne(gradeQuery);
        if (grade == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "成绩不存在");
        }
        if (gradeUpdateRequest.getGradeType() == "期中成绩") {
            gradeUpdateRequest.setGradeType(GradeConstant.MIDDLE);
        }
        switch (gradeUpdateRequest.getGradeType()) {
            case "期末成绩":
                gradeUpdateRequest.setGradeType(GradeConstant.FINAL);
                break;
            case "期中成绩":
                gradeUpdateRequest.setGradeType(GradeConstant.MIDDLE);
                break;
            case "实验成绩":
                gradeUpdateRequest.setGradeType(GradeConstant.PROJECT);
                break;
            case "测验成绩":
                gradeUpdateRequest.setGradeType(GradeConstant.TEST);
                break;
        }
        if (gradeUpdateRequest.getGradeType() != null || gradeUpdateRequest.getGradeType().equals("")) {
            gradeUpdateRequest.setGradeType(grade.getGradeType());
        }
        // BigDecimal zero = BigDecimal.ZERO;
        BigDecimal epsilon = new BigDecimal("0.0001"); // 定义一个小的误差范围
        if (gradeUpdateRequest.getScore() == null || gradeUpdateRequest.getScore().abs().compareTo(epsilon) <= 0) {
            gradeUpdateRequest.setScore(grade.getScore());
        }

        if (gradeUpdateRequest.getComment() == null || gradeUpdateRequest.getComment().equals("")) {
            gradeUpdateRequest.setComment(grade.getComment());
        }

        BeanUtils.copyProperties(gradeUpdateRequest, grade);
        boolean result = gradeService.updateById(grade);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "更新成绩失败");
        return ResultUtils.success(result);
    }

    /**
     * 分页获取全部成绩（仅管理员）
     *
     * @param gradeQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @ApiOperation(value = "分页获取全部成绩（所有人）")
    public BaseResponse<Page<GradeVO>> listUserByPage(@RequestBody GradeQueryRequest gradeQueryRequest) {
        long current = gradeQueryRequest.getCurrent() == 0 ? 1 : gradeQueryRequest.getCurrent();
        long size = gradeQueryRequest.getPageSize() == 0 ? 10 : gradeQueryRequest.getPageSize();
        Page<GradeVO> pageParam = new Page<>(current, size);
        Page<GradeVO> gradeVOPage = gradeService.getQueryWrapper(pageParam, gradeQueryRequest);
        return ResultUtils.success(gradeVOPage);
    }

    /**
     * 分页获取用户自己的成绩
     *
     * @param gradeQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/my")
    @ApiOperation(value = "分页获取用户自己的成绩（弃用）")
    public BaseResponse<Page<GradeVO>> listGradeVOByMy(@RequestBody GradeQueryRequest gradeQueryRequest,
            HttpServletRequest request) {
        if (gradeQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long current = gradeQueryRequest.getCurrent() == 0 ? 1 : gradeQueryRequest.getCurrent();
        long size = gradeQueryRequest.getPageSize() == 0 ? 10 : gradeQueryRequest.getPageSize();
        Page<GradeVO> pageParam = new Page<>(current, size);
        User loginUser = userService.getLoginUser(request);
        String username = loginUser.getUserName();
        Page<GradeVO> gradeVOPage = gradeService.getQueryWrapperByMy(pageParam, gradeQueryRequest, username);
        return ResultUtils.success(gradeVOPage);
    }

    // endregion

    /**
     * Excel导出（所有人）
     *
     * @param response
     */
    @GetMapping("/export")
    @ApiOperation(value = "Excel导出（所有人）")
    public void export(HttpServletResponse response) {
        try {
            List<Map<String, Object>> list = CollUtil.newArrayList();

            List<GradeVO> all = gradeService.getQueryWrapperByExecl();
            for (GradeVO grade : all) {
                Map<String, Object> row1 = new LinkedHashMap<>();
                row1.put("学生姓名", grade.getStudentName());
                row1.put("课程名称", grade.getCourseName());
                row1.put("课程成绩", grade.getScore());
                row1.put("成绩类型", grade.getGradeType());
                row1.put("老师评语", grade.getComment());
                row1.put("成绩时间", grade.getCreateTime());
                list.add(row1);
            }

            // 2. 写excel
            ExcelWriter writer = ExcelUtil.getWriter(true);
            writer.write(list, true);

            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            String fileName = java.net.URLEncoder.encode("学生成绩", StandardCharsets.UTF_8.toString()).replaceAll("\\+",
                    "%20");
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");

            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            writer.close();
        } catch (IOException e) {
            // 记录日志，比如使用日志框架记录详细的IO异常信息
            log.error("Excel导出时出现IO异常", e);
            // 可以考虑设置响应状态码为错误码，并返回给前端一个简单的错误提示信息
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            try {
                response.getWriter().write("Excel导出出现异常，请稍后重试");
            } catch (IOException ex) {
                log.error("设置错误提示信息到响应时出现IO异常", ex);
            }
        } catch (Exception e) {
            // 处理其他可能的异常，同样记录日志并返回合适的提示信息等
            log.error("Excel导出过程中出现其他异常", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            try {
                response.getWriter().write("Excel导出出现异常，请稍后重试");
            } catch (IOException ex) {
                log.error("设置错误提示信息到响应时出现IO异常", ex);
            }
        }
    }

    @PostMapping("/import")
    @ApiOperation(value = "Excel导入（仅老师和管理员）")
    public BaseResponse<?> upload(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        List<List<Object>> lists = ExcelUtil.getReader(inputStream).read(1);
        List<Grade> saveList = new ArrayList<>();

        for (List<Object> row : lists) {
            GradeVO gradeVO = new GradeVO();
            gradeVO.setStudentName(row.get(0).toString());
            gradeVO.setCourseName(row.get(1).toString());
            gradeVO.setScore(new BigDecimal(row.get(2).toString())); // 使用 BigDecimal 而不是 Integer
            gradeVO.setGradeType(row.get(3).toString());
            gradeVO.setComment(row.get(4).toString());
            gradeVO.setCreateTime(new Date()); // 设置当前时间为创建时间

            // 根据 gradeType 设置对应的常量值
            switch (gradeVO.getGradeType()) {
                case "期末成绩":
                    gradeVO.setGradeType(GradeConstant.FINAL);
                    break;
                case "期中成绩":
                    gradeVO.setGradeType(GradeConstant.MIDDLE);
                    break;
                case "实验成绩":
                    gradeVO.setGradeType(GradeConstant.PROJECT);
                    break;
                case "测验成绩":
                    gradeVO.setGradeType(GradeConstant.TEST);
                    break;
                default:
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "未知的成绩类型: " + gradeVO.getGradeType());
            }

            Grade grade = new Grade();
            BeanUtils.copyProperties(gradeVO, grade);

            // 查询课程
            QueryWrapper<Course> queryCourse = new QueryWrapper<>();
            queryCourse.eq("courseName", gradeVO.getCourseName());
            List<Course> courses = courseService.list(queryCourse);
            if (courses.isEmpty()) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到课程: " + gradeVO.getCourseName());
            } else if (courses.size() > 1) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "查询结果不唯一: " + gradeVO.getCourseName());
            }
            Course course = courses.get(0);
            grade.setCourseId(course.getCourseId());

            QueryWrapper<User> queryUser = new QueryWrapper<>();
            queryUser.eq("userName", gradeVO.getStudentName());
            User user = userService.getOne(queryUser);
            if (user == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "未找到学生: " + gradeVO.getStudentName());
            }

            grade.setStudentId(user.getId());

            saveList.add(grade);
        }

        boolean result = gradeService.saveBatch(saveList); // 批量保存到数据库
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "导入失败");

        return ResultUtils.success(result);
    }

}
